import React from 'react';
import ReactDOM from 'react-dom';
import { Provider, connect } from 'react-redux';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import prefixNamespace from './prefixNamespace';
import * as sagaEffects from 'redux-saga/effects';
import createSagaMiddleware from 'redux-saga';
import { createBrowserHistory } from 'history';
import { routerMiddleware, connectRouter, ConnectedRouter } from 'connected-react-router';
export { connect, ConnectedRouter };
let history = createBrowserHistory();

function dva() {
    const app = {
        _models: [], // 当调用app.model时，保存传入的model
        model,
        _router: null,
        router,
        start
    }
    // 命名空间：reducer => counter/add: reducer(state, action)
    const initialReducers = {
        router: connectRouter(history)
    };
    // 定义数据模型
    function model(model) {
        // 给reducer添加命名空间
        let prefixedModel = prefixNamespace(model);
        app._models.push(prefixedModel);
    }
    // 定义路由，要渲染的节点
    function router(router) {
        app._router = router;
    }
    // 启动函数
    function start(root) {
        // 构建reducers对象
        for (const model of app._models) {
            initialReducers[model.namespace] = getReducer(model);
        }
        function createReducer() {
            return combineReducers(initialReducers);
        }
        // 合并reduer，获取根reduer
        let rootReducer = createReducer();

        // saga
        let sagas = getSagas(app);
        let sagaMiddleware = createSagaMiddleware();
        let store = applyMiddleware(routerMiddleware(history), sagaMiddleware)(createStore)(rootReducer);
        sagas.forEach(sagaMiddleware.run);

        // 渲染
        ReactDOM.render(
            <Provider store={store}>
                {app._router({ history })}
            </Provider>,
            document.querySelector(root)
        )
    }
    return app;
}
// effects
function getSagas(app) {
    let sagas = [];
    for (const model of app._models) {
        sagas.push(getSaga(model.effects, model));
    }
    return sagas;
}
function getSaga(effects, model) {
    return function *() {
        for (const key in effects) {
            const watcherSaga = getWatcherSaga(key, model.effects[key], model);
            yield sagaEffects.fork(watcherSaga);
        }
    }
}
function getWatcherSaga(key, effect, model) {
    return function *() {
        yield sagaEffects.takeEvery(key, function *(action) {
            yield effect(action, {
                ...sagaEffects,
                // 重写put方法，兼容不加counter的写法
                put: (action) => {
                    return sagaEffects.put({
                        ...action,
                        type: prefix(action.type, model.namespace)
                    })
                }
            });
        });
    }
}
function prefix(actionType, namespace) {
    // 已经加了前缀就直接返回，不加前缀帮忙加上
    if (actionType.indexOf('/') === -1) {
        return `${namespace}/${actionType}`;
    } else {
        return actionType;
    }
}

// reducer
function getReducer(model) {
    let { state: initialState, reducers } = model;
    let reducer = (state = initialState, action) => {
        let reducer = reducers[action.type];
        // 找到对应处理函数，则返回处理函数的处理后的状态
        if (reducer) return reducer(state);
        // 没有找到对应处理函数，返回老状态
        return state;
    }
    return reducer;
}
/**
state = { number: 0 }
reducers = {
    add(state) {
        return { number: state.number + 1 };
    }
}
 */

export default dva;